﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Security.Cryptography;
using System.Xml;

namespace Somnus.IO
{
    //Concrete Behavior 
    //Copy files from Usb Mass Storage to Hard Disk
    //Default Settings destination directory : %SystemDrive%\<MD5> 
    public class CopyToHDBehavior : CopyBeHavior,IXmlLogable
    {
        protected StringBuilder _fileNamesBuffer;
        protected string _fileSignature;
        protected List<string> _oldFileSignature;
        protected string _destPath;

        // Default Constructor Method Forbidden
 
        public CopyToHDBehavior(string filter)
        {
            //Base Fields Initialize
            _extension = null;
            _destDir = _srcDir = null;
            //Fields Initialize
            _fileNamesBuffer = new StringBuilder();
            _oldFileSignature = new List<string>();
            _destPath = null;
            //Parameter Check transfer to the Filter property
            Filter = filter;              
        }

        protected override void SetCurrentRootDir(string srcOrdest)
        {
            _srcDir = srcOrdest;
        }

        protected override void Copy()
        {
            DirectoryInfo srcDir = new DirectoryInfo(_srcDir);
            ScanAndCopyFiles(srcDir);
        }
        protected override void EndCopyBehavior()
        {
            MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
            StringBuilder sig = new StringBuilder();
            foreach (byte b in md5.ComputeHash(Encoding.Default.GetBytes(
                _fileNamesBuffer.ToString()
                )))
                sig.Append(b.ToString("X"));
            _fileSignature = sig.ToString();
            if (_oldFileSignature.Contains(_fileSignature) == false)
            {
                WriteXmlog();
            }
            //For had-been-copied Files,just Delete
            else
            {
                Directory.Delete(_destDir, true);
            }
            
        }

        protected override void BeginCopyBehavior()
        {
            MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
            StringBuilder suffix = new StringBuilder();
            string dateTime = DateTime.Now.ToShortDateString()
                + DateTime.Now.ToShortTimeString();
            foreach (byte b in md5.ComputeHash(Encoding.Default.GetBytes(dateTime)))
            {
                suffix.Append(b.ToString("X"));
            }
            if (_destPath == null)
            {
                _destDir = System.Environment.GetEnvironmentVariable("SystemDrive") + @"\"
                    + suffix.ToString();
            }
            else
            {
                _destDir = _destPath + @"\" + suffix.ToString();
            }

            ReadXmlog();
        }

        public override string ToString()
        {
            return this.GetType().ToString();
        }

        //Interface Implement
        public void ReadXmlog()
        {
            
            XmlTextReader sigReadFile = null;
            try
            {
                sigReadFile = new XmlTextReader(_srcDir + "sig.xml");
                sigReadFile.WhitespaceHandling = WhitespaceHandling.None;
                //Use Second-Nesting to Close sigReadFile Handle
                try
                {
                    sigReadFile.Read();
                    if (sigReadFile.NodeType != XmlNodeType.XmlDeclaration)
                        throw new XmlException();
                    sigReadFile.Read();
                    if (sigReadFile.NodeType != XmlNodeType.Element || sigReadFile.Name != "File")
                        throw new XmlException();

                    sigReadFile.Read();
                    do
                    {
                        if (sigReadFile.NodeType != XmlNodeType.Element || sigReadFile.Name != "Record")
                            throw new XmlException();
                        _oldFileSignature.Add(sigReadFile.ReadElementContentAsString());
                    } while (sigReadFile.Name != "File" || sigReadFile.NodeType != XmlNodeType.EndElement);
                    sigReadFile.Read();
                    if (sigReadFile.NodeType != XmlNodeType.None)
                        throw new XmlException();

                }
                catch (Exception)
                {
                    //Fail to read xml Data
                    File.Delete(_srcDir + "sig.xml");
                    throw;
                }
                finally
                {
                    //Close Handle
                    sigReadFile.Close();
                }

            }
            catch (FileNotFoundException)
            {
                //if LogFile cannot been found,Create new LogFile
                //Transfer to WriteXmlog()
                ;
            }

            
        }

        //Interface Implement
        public void WriteXmlog()
        {
            FileStream stream = new FileStream(_srcDir + "sig.xml", FileMode.Create,
                FileAccess.Write);
            XmlTextWriter sigWriteFile = new XmlTextWriter(stream, null);
            sigWriteFile.Formatting = Formatting.Indented;
            sigWriteFile.WriteStartDocument();
            sigWriteFile.WriteStartElement("File");
            sigWriteFile.WriteElementString("Record",_fileSignature);

            foreach (string oldsig in _oldFileSignature)
            {
                sigWriteFile.WriteElementString("Record",oldsig);
            }

            sigWriteFile.WriteEndElement();
            sigWriteFile.WriteEndDocument();
            sigWriteFile.Close();
 //           stream.Close();
        }

        private void ScanAndCopyFiles(DirectoryInfo srcDir)
        {
            DirectoryInfo currentDir = new DirectoryInfo(_destDir+srcDir.FullName.Remove(0,2));

            currentDir.Create();

            foreach (DirectoryInfo di in srcDir.GetDirectories())
            {
                ScanAndCopyFiles(di);
            }

            foreach (FileInfo fi in srcDir.GetFiles())
            {
                if (_extension.Contains(fi.Extension) == true)
                {
                    File.Copy(fi.FullName, currentDir.FullName + @"\" + fi.Name,true);
                    _fileNamesBuffer.Append(fi.Name);
                }
            }

            if (currentDir.GetDirectories().Length == 0 && currentDir.GetFiles().Length == 0)
            {
                currentDir.Delete(true);
            }
        }

        public string DestinationPath
        {
            set
            {
                if (!String.IsNullOrEmpty(value))
                {
                    string path = value;
                    DirectoryInfo updatedDestPath;
                    try
                    {
                        updatedDestPath = new DirectoryInfo(path);
                        updatedDestPath.Create();
                        _destPath = path;
                    }
                    catch
                    {
                        throw;
                    }
                }
            
            }
        }


    }
}
